﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
using Coolite.Ext.Web;
using Pap.Data;
using Pap.Web.Modules.Administration.ViewModel;
using Pap.Web.Utils;
using Utils.UIPermission;

namespace Pap.Web.Modules.Administration.Views
{
    /// <summary>
    /// 
    /// </summary>
    public partial class ProjectDetails : Pap.Web.Utils.BasePage<ProjectDetailsViewModel>, IPermittedPage
    {
        #region QueryString

        /// <summary>
        /// Gets the project ID.
        /// </summary>
        public string ProjectID
        {
            get
            {
                return Request.QueryString["ProjectID"];
            }
        }

        #endregion

        #region ViewState

        /// <summary>
        /// Gets the project stages.
        /// </summary>
        public List<object> ProjectStages
        {
            get
            {
                if (ViewState["ProjectStages"] == null)
                    ViewState.Add("ProjectStages", new List<object>());
                return ViewState["ProjectStages"] as List<object>;
            }
        }

        /// <summary>
        /// Gets the removed stages.
        /// </summary>
        public List<int> RemovedStages
        {
            get
            {
                if (ViewState["RemovedStages"] == null)
                    ViewState.Add("RemovedStages", new List<int>());
                return ViewState["RemovedStages"] as List<int>;
            }
        }

        #endregion

        #region [ Events ]

        /// <summary>
        /// Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Ext.IsAjaxRequest && !IsPostBack)
            {
                if (this.ViewModel != null)
                {
                    IProjectStage stage = this.ViewModel.GetLastStage();
                    if (stage != null)
                    {
                        txtStageNumber.Text = (stage.Stage + 1).ToString();
                        txtFrom.MinValue = stage.To;
                        txtParent.Text = stage.ProjectObj.ProjectName;

                        txtLastStage.Text = stage.Stage.ToString();
                    }
                    else
                    {
                        txtStageNumber.Text = "1";
                        txtFrom.MinValue = 0;
                        txtParent.Text = "";
                    }

                    if (!string.IsNullOrEmpty(ProjectID))
                    {
                        FillControls(this.ViewModel.GetProjectById(ProjectID.ToGuid()));
                    }
                }
            }
        }

        /// <summary>
        /// Handles the Clicked event of the btnAdd control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Coolite.Ext.Web.AjaxEventArgs"/> instance containing the event data.</param>
        protected void btnAdd_Clicked(object sender, AjaxEventArgs e)
        {
            int stageNumber;
            double stageTo;
            AddStage(out stageNumber, out stageTo);

            SetStagesLogic(stageNumber, stageTo);

            ClearStageData();

            RefreshStagesGrid();
        }

        /// <summary>
        /// Handles the Clicked event of the btnSubmit control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Coolite.Ext.Web.AjaxEventArgs"/> instance containing the event data.</param>
        protected void btnSubmit_Clicked(object sender, AjaxEventArgs e)
        {
            this.Validate();
            if (this.IsValid)
            {
                try
                {
                    if (!string.IsNullOrEmpty(ProjectID))
                    {
                        this.ViewModel.UpdateProject(ProjectID.ToGuid(), txtProjectName.Text, txtProfitPercent.Text, RemovedStages, ProjectStages);
                        LoadStagesIntoViewState();
                        //--------------------------------------------------------------
                        Ext.Redirect("~/Administration.route/ProjectsList", GetLocalResourceObject("MSGRedirecting").ToString());
                    }
                    else
                    {
                        this.ViewModel.InsertProject(txtProjectName.Text, txtProfitPercent.Text, txtParent.Text, ProjectStages);
                        //--------------------------------------------------------------
                        ClearControls();
                        Ext.Msg.Alert(GetLocalResourceObject("MBDoneCaption").ToString(), GetLocalResourceObject("MBDoneText").ToString()).Show();
                    }

                    FormStatusBar.SetStatus(new StatusBarStatusConfig { Text = GetLocalResourceObject("MBDoneText").ToString(), IconCls = "", Clear2 = true });
                }
                catch
                {
                    Ext.Msg.Alert(GetLocalResourceObject("MBErrorCaption").ToString(), GetLocalResourceObject("MBCantSave").ToString()).Show();
                    FormStatusBar.SetStatus(new StatusBarStatusConfig { Text = GetLocalResourceObject("MBCantSave").ToString(), IconCls = "", Clear2 = true });
                }
            }
            else
            {
                FormStatusBar.SetStatus(new StatusBarStatusConfig { Text = GetLocalResourceObject("MBFormInvalid").ToString(), IconCls = "", Clear2 = true });
            }
        }

        /// <summary>
        /// Handles the Clicked event of the btnCancel control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Coolite.Ext.Web.AjaxEventArgs"/> instance containing the event data.</param>
        protected void btnCancel_Clicked(object sender, AjaxEventArgs e)
        {
            Ext.Redirect("~/Administration.route/ProjectsList", GetLocalResourceObject("MSGRedirecting").ToString());
        }

        /// <summary>
        /// Handles the Validate event of the txtProjectName control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Web.UI.WebControls.ServerValidateEventArgs"/> instance containing the event data.</param>
        protected void txtProjectName_Validate(object sender, ServerValidateEventArgs e)
        {
            if (!ValidateName())
            {
                e.IsValid = false;
            }
        }

        /// <summary>
        /// Validates the stages.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Web.UI.WebControls.ServerValidateEventArgs"/> instance containing the event data.</param>
        protected void ValidateStages(object sender, ServerValidateEventArgs e)
        {
            if (StagesStore.Reader.Count < 1)
            {
                e.IsValid = false;
                txtProjectName.MarkInvalid(GetLocalResourceObject("MBNoStagesAdded").ToString());
            }
            else txtProjectName.ClearInvalid();
        }

        #region [ StageWindow ]

        /// <summary>
        /// Handles the Command event of the gvStages control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Coolite.Ext.Web.AjaxEventArgs"/> instance containing the event data.</param>
        protected void gvStages_Command(object sender, AjaxEventArgs e)
        {
            RowSelectionModel model = gvStages.SelectionModel.Primary as RowSelectionModel;
            int stage = int.Parse(e.ExtraParams["Stage"].ToString());

            if (e.ExtraParams["CommandName"].Equals("Edit"))
            {
                OpenEditStageWindow(stage);
            }
        }

        /// <summary>
        /// Opens the edit stage window.
        /// </summary>
        /// <param name="stageNumber">The stage number.</param>
        private void OpenEditStageWindow(int stageNumber)
        {
            //set minimum value
            IProjectStage previousStage = GetStageByNumber(stageNumber - 1);
            if (previousStage == null)
                wndtxtFrom.MinValue = 0;
            else wndtxtFrom.MinValue = previousStage.To;

            //set the maximum values
            IProjectStage nextStage = GetStageByNumber(stageNumber + 1);
            if (nextStage != null)
                wndtxtTo.MaxValue = nextStage.From;
            else wndtxtTo.MaxValue = double.MaxValue;

            //fill the window
            IProjectStage projectStage = GetStageByNumber(stageNumber);
            wndtxtStage.Text = stageNumber.ToString();
            wndtxtAgeLimit.Text = projectStage.AgeLimit.ToString();
            wndtxtFrom.Text = projectStage.From.ToString();
            wndtxtTo.Text = projectStage.To.ToString();
            //-----------show window-----------
            wndEditStage.Expand(true);
            wndEditStage.Show();
        }

        /// <summary>
        /// Handles the Clicked event of the wndbtnSubmit control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Coolite.Ext.Web.AjaxEventArgs"/> instance containing the event data.</param>
        protected void wndbtnSubmit_Clicked(object sender, AjaxEventArgs e)
        {
            int stageNumber = wndtxtStage.Text.ToInt32();
            double stageTo = double.Parse(wndtxtTo.Text);
            foreach (object[] stageObj in ProjectStages)
            {
                if ((int)stageObj[0] == stageNumber)
                {
                    stageObj[1] = wndtxtAgeLimit.Text.ToInt32();
                    stageObj[2] = double.Parse(wndtxtFrom.Text);
                    stageObj[3] = stageTo;
                    break;
                }
            }
            SetStagesLogic(stageNumber, stageTo);
            RefreshStagesGrid();
            wndEditStage.Collapse(true);
            wndEditStage.Hide();
        }

        /// <summary>
        /// Handles the Clicked event of the wndbtnCancel control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Coolite.Ext.Web.AjaxEventArgs"/> instance containing the event data.</param>
        protected void wndbtnCancel_Clicked(object sender, AjaxEventArgs e)
        {
            wndEditStage.Collapse(true);
            wndEditStage.Hide();
        }

        #endregion

        #endregion

        #region [ Functions ]

        /// <summary>
        /// Loads the state of the stages into view.
        /// </summary>
        private void LoadStagesIntoViewState()
        {
            IProject project = this.ViewModel.GetProjectById(ProjectID.ToGuid());
            foreach (var stage in project.Stages)
            {
                ProjectStages.Add(new object[] { stage.Stage, stage.AgeLimit, stage.From, stage.To, stage.ProjectStageID, stage.ProjectID });
            }
        }

        /// <summary>
        /// Fills the controls.
        /// </summary>
        /// <param name="project">The project.</param>
        private void FillControls(IProject project)
        {
            txtProjectName.Text = project.ProjectName;
            txtProfitPercent.Text = project.ProfitPercent.ToString();
            if (project.ParentProject != null)
                txtParent.Text = project.ParentProject.ProjectName;
            else txtParent.Text = "";
            //----------------------------------------------------------
            //show stages
            foreach (var stage in project.Stages)
            {
                ProjectStages.Add(new object[] { stage.Stage, stage.AgeLimit, stage.From, stage.To, stage.ProjectStageID, stage.ProjectID });
            }
            RefreshStagesGrid();
            //----------------------------------------------------------
            if (ViewModel.GetNextStage(project.Stages.Last()) != null)
            {
                HideAddingHeader();
            }
        }

        /// <summary>
        /// Hides the adding header.
        /// </summary>
        private void HideAddingHeader()
        {
            btnAdd.Visible = false;
            txtStageNumber.Visible = false;
            txtAgeLimit.Visible = false;
            txtFrom.Visible = false;
            txtTo.Visible = false;
        }

        /// <summary>
        /// Adds the stage.
        /// </summary>
        /// <param name="stageNumber">The stage number.</param>
        /// <param name="stageTo">The stage to.</param>
        private void AddStage(out int stageNumber, out double stageTo)
        {
            object[] stage = new object[6];
            stageNumber = int.Parse(txtStageNumber.Text);
            stageTo = double.Parse(txtTo.Text);
            stage[0] = stageNumber;
            stage[1] = int.Parse(txtAgeLimit.Text);
            stage[2] = double.Parse(txtFrom.Text);
            stage[3] = stageTo;
            stage[4] = Guid.Empty;
            stage[5] = Guid.Empty;

            ProjectStages.Add(stage);
        }

        /// <summary>
        /// Deletes the stage.
        /// </summary>
        /// <param name="str">The STR.</param>
        [AjaxMethod]
        public void DeleteStage(string str)
        {
            if (str == "yes")
            {
                object[] stage = ProjectStages.Last() as object[];
                ProjectStages.RemoveAt(ProjectStages.Count - 1);
                if ((Guid)stage[4] != Guid.Empty)
                    RemovedStages.Add((int)stage[0]);

                RefreshStagesGrid();

                int stageNumber = (int)stage[0];
                //set the new stage number
                txtStageNumber.Text = (stageNumber).ToString();
                //set the last stage number
                txtLastStage.Text = (stageNumber - 1).ToString();

                IProjectStage previousStage = GetStageByNumber(stageNumber - 1);
                if (previousStage != null)
                    txtFrom.MinValue = previousStage.To;
                else txtFrom.MinValue = 0;
            }
        }

        /// <summary>
        /// Sets the stages logic.
        /// </summary>
        /// <param name="stageNumber">The stage number.</param>
        /// <param name="stageTo">The stage to.</param>
        private void SetStagesLogic(int stageNumber, double stageTo)
        {
            if (stageNumber == (int)(ProjectStages.Last() as object[])[0])
            {
                txtLastStage.Text = stageNumber.ToString();
                txtStageNumber.Text = (stageNumber + 1).ToString();
                txtFrom.MinValue = stageTo;
            }
        }

        /// <summary>
        /// Clears the stage data.
        /// </summary>
        private void ClearStageData()
        {
            txtAgeLimit.Reset();
            txtFrom.Reset();
            txtTo.Reset();
        }

        /// <summary>
        /// Refreshes the stages grid.
        /// </summary>
        private void RefreshStagesGrid()
        {
            StagesStore.DataSource = ProjectStages.ToArray();
            StagesStore.DataBind();
        }

        /// <summary>
        /// Clears the controls.
        /// </summary>
        private void ClearControls()
        {
            txtParent.Text = txtProjectName.Text;
            txtProjectName.Reset();
            txtProfitPercent.Reset();
            ProjectStages.Clear();
            RefreshStagesGrid();
        }

        /// <summary>
        /// Gets the stage by number.
        /// </summary>
        /// <param name="stageNumber">The stage number.</param>
        /// <returns></returns>
        private IProjectStage GetStageByNumber(int stageNumber)
        {
            IProjectStage projectStage = null;
            //------------------------------------------------------
            //search current stages in session
            foreach (object[] stage in ProjectStages)
            {
                if ((int)stage[0] == stageNumber)
                {
                    projectStage = this.ViewModel.GetInstance<IProjectStage>();
                    projectStage.Stage = (int)stage[0];
                    projectStage.AgeLimit = (int)stage[1];
                    projectStage.From = (double)stage[2];
                    projectStage.To = (double)stage[3];
                    projectStage.ProjectStageID = (Guid)stage[4];
                    projectStage.ProjectID = (Guid)stage[5];
                    break;
                }
            }
            //------------------------------------------------------
            //search in db
            if (projectStage == null)
            {
                projectStage = ViewModel.GetStageByNumber(stageNumber);
                if (projectStage != null)
                {
                    if (RemovedStages.Contains(projectStage.Stage))
                        projectStage = null;
                }
            }
            return projectStage;
        }

        /// <summary>
        /// Validates the name.
        /// </summary>
        /// <returns></returns>
        [AjaxMethod]
        public bool ValidateName()
        {
            if (!string.IsNullOrEmpty(txtProjectName.Text))
            {
                bool valid = true;
                if (string.IsNullOrEmpty(ProjectID))
                {
                    if (this.ViewModel.DoesProjectNameExist(txtProjectName.Text, null))
                    {
                        valid = false;
                        txtProjectName.MarkInvalid(GetLocalResourceObject("MsgProjectNameIsUsed").ToString());
                    }
                }
                else
                {
                    if (this.ViewModel.DoesProjectNameExist(txtProjectName.Text, ProjectID.ToGuid()))
                    {
                        valid = false;
                        txtProjectName.MarkInvalid(GetLocalResourceObject("MsgProjectNameIsUsed").ToString());
                    }
                }
                return valid;
            }
            return true;
        }

        #endregion

        #region IPermittedPage Members

        /// <summary>
        /// Gets the name of the permission.
        /// </summary>
        /// <value>
        /// The name of the permission.
        /// </value>
        public string PermissionName
        {
            get { return "ProjectDetails"; }
        }

        #endregion
    }
}
